# -*- coding: utf-8 -*-            
# @Author : HJH
# @Time : 2024/1/20 18:14
# @Use :
import copy
import datetime
import json
import time

import requests
import schedule
from loguru import logger
from topsdk.client import TopApiClient, TopException
from topsdk.defaultability.defaultability import Defaultability
from topsdk.defaultability.request.alitrip_policy_special_upload_request import *
from tqdm import tqdm


def log_config():
    # 自定义日志格式
    # logger.remove()
    # logger_format = "{time} | {level} | {thread.name} | {file}:{function}:{line} - {message}"

    # 添加输出处理程序，将日志输出到文件
    logger.add("./logs/xc_info_file.log", level="INFO")
    logger.add("./logs/xc_error_file.log", level="ERROR")


def send_xcapi_request():
    """
    发送请求的函数，这里使用requests库发送请求。
    :return: pandas df对象
    """
    url = "http://192.168.110.135:9093/static/price/getXcData"

    headers = {"content-type": "application/json"}

    logger.info("携程产品数据请求中... ...")
    response = requests.request("GET", url, headers=headers, timeout=10000)
    # logger.info(response.text)
    # 检查响应状态码是否为200
    if response.status_code == 200:
        rs_json = json.loads(response.text)
        # logger.info('南航R舱数据请求成功：{}'.format(rs_json))
        return rs_json

    else:
        logger.error('携程产品数据请求失败：{}'.format(response.text))
        raise RuntimeError("发生错误，程序停止")


def send_fzapi_request(request):
    """
    发送请求
    :return:
    """
    # create Client
    client = TopApiClient(appkey='25346003', app_sercet='aeda58e87f78ea981a141ac507e5a940',
                          top_gateway_url='http://39.98.61.147/huifei/',
                          verify_ssl=False)
    ability = Defaultability(client=client)

    # 将 policy_request 转换为 JSON 字符串
    # json_data = json.dumps(request.to_dict())
    logger.info("【飞猪特殊政策上传请求】: 请求中... ...")

    """
    请求接口
    """
    max_tries = 5  # 最大尝试次数
    num_tries = 0  # 已尝试次数
    sleep_time2 = 3  # 设置等待时间
    while num_tries < max_tries:
        try:
            response = ability.alitrip_policy_special_upload(request,
                                                             '6102a098713e7108013e55b21b78e46c0f649d29cd2fedf4259705970')
            logger.info(f"【飞猪特殊政策上传响应】: {response}")
            flag1 = response.get('result', {}).get('data', {}).get('create_result', {}).get('success')
            flag2 = response.get('result', {}).get('data', {}).get('delete_result', {}).get('success')
            if not (flag1 or flag2):
                num_tries += 1
                if num_tries >= max_tries:
                    # 如果已经尝试到最大次数，跳出循环，放弃重试
                    logger.error(f"重试{max_tries}次后仍然失败，放弃重试。")
                    break
                continue
            return  # 成功请求到数据，直接返回
        except (TopException, requests.exceptions.RequestException) as e:
            logger.error(e)
            num_tries += 1
            if num_tries >= max_tries:
                # 如果已经尝试到最大次数，跳出循环，放弃重试
                logger.error(f"重试{max_tries}次后仍然失败，放弃重试。")
                break
            # 打印日志，并且睡眠
            logger.info(f"请求失败，休眠 {sleep_time2} 秒后进行第 {num_tries + 1} 次尝试。")
            time.sleep(sleep_time2)


def add_policy(pds: list):
    """
    普通政策上传参数
    :param pds:
    :return:
    """
    policyCreateRequestDto = AlitripPolicySpecialUploadPolicyCreateRequestDto()
    # 行程类型
    policyCreateRequestDto.trip_type = 0
    # 店铺id
    policyCreateRequestDto.agent_id = 5252
    # 操作类型：ADD，增量；FULL，全量
    policyCreateRequestDto.exec_type = 'ADD'
    # 政策类型：P，普通政策；T，特殊政策；G，规则政策；
    policyCreateRequestDto.policy_type = 'T'
    # 商家传入时间
    policyCreateRequestDto.agent_send_time = datetime.now()
    # 需要导入的政策列表
    policyCreateRequestDto.policy_list = pds
    policyCreateRequestDto.delete_policy = []

    """
    将参数转为二进制文件的数据
    """
    request = AlitripPolicySpecialUploadRequest()
    request.param_policy_create_request_d_t_o = policyCreateRequestDto
    return request


def process_row(row):
    """
    定义一个函数，传入一行数据，转化为PolicyDto需要导入的政策
    :param pc: 政策代码
    :param row:飞猪模板数据
    :return:飞猪接口需要的PolicyDto数据
    """
    """
    行程信息
    """
    flightDTO = AlitripPolicySpecialUploadFlightDTO()
    # 允许航班号
    flightDTO.allow_flight_num = str(row.get('flightNo')[-4:])
    # 去程舱位
    flightDTO.cabin = row.get('cabin')
    # 去程班期限制
    flightDTO.day_week = [1, 2, 3, 4, 5, 6, 7]
    # 行程类型标记：0，单程；1，往返
    flightDTO.flight_index = 0
    """
    允许航班日期
    """
    allowTravelDate = AlitripPolicySpecialUploadDatePairDto()
    # 根据"-"进行分割字符串
    allowTravelDate.start = datetime.strptime(row.get('depDate'), "%Y-%m-%d").replace(hour=00, minute=00,
                                                                                      second=00)
    allowTravelDate.end = datetime.strptime(row.get('depDate'), "%Y-%m-%d").replace(hour=23, minute=59, second=59)
    flightDTO.allow_travel_date = [allowTravelDate]

    """
    竞价信息
    """
    priceDto = AlitripPolicySpecialUploadPriceDto()
    # 代理费率
    priceDto.commission = 0
    # 留钱
    priceDto.return_price = -1 * 100
    # 儿童价计算方法
    priceDto.child_sale_type = 4
    # 免费托运行李额
    priceDto.baggage = 0
    # 固定金额竞价空间
    priceDto.bidd_fee = 24 * 100

    """
    销售信息
    """
    saleDto = AlitripPolicySpecialUploadSaleDto()
    # 提前预定天数 只能输入A-B的格式，并且A、B都是0到365之间的整数
    saleDto.advance_day = '5-365'
    # 销售方式 0 无， 1 打包销售套餐1， 2 打包销售套餐2， 3 打包销售套餐3， 4 返现-航司运价，5 返现-销售方包装
    saleDto.sale_mode_code = 0
    """
    销售日期
    """
    saleDate = AlitripPolicySpecialUploadDatePairDto()
    # 根据"-"进行分割字符串
    saleDate.start = datetime.now().replace(hour=00, minute=00, second=00)
    saleDate.end = datetime.now().replace(hour=23, minute=59, second=59)
    saleDto.sale_date = [saleDate]

    """
    乘机人信息
    """
    passengerDto = AlitripPolicySpecialUploadPassengerDto()
    # 产品类型
    passengerDto.product_code = 0

    """
    需要导入的政策列表
    """
    policyDto = AlitripPolicySpecialUploadPolicyDto()
    # 政策id
    policyDto.policy_code = xc_p_c
    # 政策状态：1，有效；2，挂起；0，删除 3，停用
    policyDto.status = 1
    # policyDto.status = 2
    # 航司代码
    policyDto.airline = 'CZ'
    # 到达机场三字码
    policyDto.arr_airport = row.get('arr')
    # 是否订位
    policyDto.create_pnr = 1
    # 出发机场三字码
    policyDto.dep_airport = row.get('dep')
    # 商家配置号
    policyDto.office_no = 'CGO104'
    # 是否需要pata验价
    policyDto.pata = 0
    # 是否支持代码共享航班
    policyDto.code_share = 0
    # 票面价
    policyDto.fare_price = int(float(row.get('costPrice')))
    # 政策备注
    policyDto.memo = row.get('price')
    # 直达中转
    policyDto.direct_transfer_type = 0
    policyDto.passenger = passengerDto
    policyDto.sale = saleDto
    policyDto.price = priceDto
    policyDto.flights = [flightDTO]
    return policyDto


def del_policy(pc):
    """
    删除政策
    """
    deletePolicy = AlitripPolicySpecialUploadPolicyQueryParamDTO()
    deletePolicy.policy_code = pc

    policyCreateRequestDto = AlitripPolicySpecialUploadPolicyCreateRequestDto()
    # 行程类型
    policyCreateRequestDto.trip_type = 0
    # 店铺id
    policyCreateRequestDto.agent_id = 5252
    # 操作类型：ADD，增量；FULL，全量
    policyCreateRequestDto.exec_type = 'ADD'
    # 政策类型：P，普通政策；T，特殊政策；G，规则政策；
    policyCreateRequestDto.policy_type = 'T'
    # 商家传入时间
    policyCreateRequestDto.agent_send_time = datetime.now()
    # # 删除政策查询参数，需要删除时execType必须为ADD
    policyCreateRequestDto.delete_policy = [deletePolicy]
    policyCreateRequestDto.policy_list = []

    """
    将参数转为二进制文件的数据
    """
    request = AlitripPolicySpecialUploadRequest()
    request.param_policy_create_request_d_t_o = policyCreateRequestDto
    return request


def get_key(item):
    return (
        item.get('depDate'), item.get('flightNo'), item.get('carrier'), item.get('dep'), item.get('arr'),
        item.get('cabin'),
        item.get('costPrice'),
        item.get('price'))


def run_data():
    # 发送请求
    xc_rs_json = send_xcapi_request()

    xc_rs_data = xc_rs_json.get('data')  # 获取列表数据
    logger.info(f"【获取列表数据长度】: {len(xc_rs_data)}")
    unique_items = set(get_key(item) for item in xc_rs_data)  # 根据字段去重
    result = [dict(zip(['depDate', 'flightNo', 'carrier', 'dep', 'arr', 'cabin', 'costPrice', 'price'], key)) for key in
              unique_items]

    # 过滤完数据长度
    logger.info(f"【去重数据长度】: {len(result)}")
    policyDtoList = []
    for item in result:
        policyDto = process_row(item)
        policyDtoList.append(policyDto)

    # # 复制 policyDtoList 列表
    # copied_list = policyDtoList.copy()
    # # 设置多种销售方式
    # for i in [1, 2, 3]:
    #     copied_nlist = copy.deepcopy(copied_list)
    #     for cp_item in copied_nlist:
    #         # 销售方式 0 无， 1 打包销售套餐1， 2 打包销售套餐2， 3 打包销售套餐3， 4 返现-航司运价，5 返现-销售方包装
    #         cp_item.sale.sale_mode_code = int(i)
    #     policyDtoList.extend(copied_nlist)

    size = 450
    total = len(policyDtoList)
    logger.info(f"【上传飞正常数据长度】: {total}")
    # 在循环外部创建进度条
    progress_bar = tqdm(total=total, desc="上传政策进度")
    for i in range(0, total, size):
        # 取出最大450条数据，添加到结果列表
        end = i + size
        subset = policyDtoList[i:end]
        # 获取请求参数
        add_req = add_policy(subset)
        send_fzapi_request(add_req)
        # 每次循环结束时更新进度条
        progress_bar.update(end - i)

    # 循环结束后关闭进度条
    progress_bar.close()


if __name__ == '__main__':
    # 初始化日志配置
    log_config()

    xc_p_c = input("请输入政策代码:")
    xc_s_t = input("请输入间隔时间:")
    xc_i_d = input("删除已上传政策数据(0否,1是):")

    # ************************* 删除政策 *************************
    if int(xc_i_d) == 1:
        del_req = del_policy(xc_p_c)
        send_fzapi_request(del_req)
        logger.info(f"删除政策成功--->{xc_p_c}")

    # ************************* 循环上传政策 *************************
    while True:
        run_data()
        logger.info(f"下次执行时间 {int(xc_s_t) * 60}秒 后... ...")
        time.sleep(int(xc_s_t) * 60)
